#include "BgmCurtainPlay.h"
#include "mediaPriv.h"
#include "CurtainActManager.h"
#include <sys/mman.h>
#include "Mp4ClientStream.h"

extern "C"
{
	#include "md5.h"
}


using namespace std;

namespace Media{

BgmCurtainPlay*            BgmCurtainPlay::sm_streamercurtainPlayIns;
std::mutex 		           BgmCurtainPlay::sm_insMutex;

BgmCurtainPlay* BgmCurtainPlay::instance()
{
	if(sm_streamercurtainPlayIns == nullptr)
    {
        std::lock_guard<std::mutex> guard(sm_insMutex);
        if(sm_streamercurtainPlayIns == nullptr)
        {
            sm_streamercurtainPlayIns = new BgmCurtainPlay();
        }
    }
    return sm_streamercurtainPlayIns;
}

BgmCurtainPlay::BgmCurtainPlay() 
{ 

}

BgmCurtainPlay::~BgmCurtainPlay() 
{ 

}

bool BgmCurtainPlay::bgmDescribeCheckout(Json::Value& streamerTable, std::string url, std::string fileName)
{
    if(!streamerTable.isMember("bgmlist") 
      || !streamerTable.isMember("type") )
	{
        LOG_PrintError("json params error\n");
        return false;
	}

	Json::Value streamInfo = streamerTable["bgmlist"];
    Json::Value detailInfo = Json::nullValue;
	for(uint i = 0; i < streamInfo.size(); ++i)
	{
        detailInfo = streamInfo[i];
        if (!detailInfo.isMember("mediasource") 
          || !detailInfo.isMember("showtime"))
        {
            LOG_PrintError("json params error\n");
            return false;
        }

        if (!detailInfo.isMember("pattern"))
        {
            if(streamerTable["type"].asString() == "online")
            {
                detailInfo["pattern"] = "ONLINEMP4"; //远程MP4
            }
            else 
            {
                detailInfo["pattern"] = "VIDEOFILE"; //本地MP4
            }
        }

        if(!url.empty() && !fileName.empty())
        {
            if(detailInfo["mediasource"] == url)
            {
                detailInfo["mediasource"] = fileName;

                detailInfo["pattern"] = "VIDEOFILE";
            }
        }       

        streamInfo[i] = detailInfo;
	}

	if(streamInfo.size() == 1
	  && (detailInfo["pattern"] == "VIDEOFILE"))
	{
        Mp4ClientStream::instance(MP4_LOCAL_BGM)->setRepetInfo(true);
	}
	else
	{
        Mp4ClientStream::instance(MP4_LOCAL_BGM)->setRepetInfo(false);
	}
	

	streamerTable["bgmlist"] = streamInfo;

	return true;
}

bool BgmCurtainPlay::updateBgmPlay()
{
    Json::Value streamer = m_bgmListTable["bgmlist"];
    Json::Value streamInfo = streamer[m_curPlayIndex];
    m_curPlayIndex = (m_curPlayIndex + 1) % streamer.size();

    std::string filePath = streamInfo["mediasource"].asString();
    std::string pattern = streamInfo["pattern"].asString();

    /*if(m_curfilePath == filePath
      && compareMd5(filePath, m_curfileMd5.c_str())
      && (m_bgmListTable["type"].asString() == "online"))
    {
        tracef("updateBgmPlay not need update\n");
        return true;
    }*/
    
    m_curfilePath = filePath;

    /* stop */
    Mp4StreamType mp4Type = MP4_ONLINE_BGM;
    if(m_playPattern == "VIDEOFILE") 
    {
        mp4Type = MP4_LOCAL_BGM;
    }
    Mp4ClientStream::instance(mp4Type)->stop();
    
    /* start */
    if(pattern == "VIDEOFILE") 
    {
        mp4Type = MP4_LOCAL_BGM;
    }
    else
    {
        mp4Type = MP4_ONLINE_BGM;
    }    
    StreamPlayInfo playInfo = {0};
    playInfo.audioChn = 15;
    playInfo.playAbility = AUDIO_ONLY;
    playInfo.task.StartTime = 0;
    playInfo.task.StopTime = -1;
    strcpy(playInfo.stream.content, filePath.c_str());
 
    Mp4ClientStream::instance(mp4Type)->start(playInfo);

    m_playPattern = pattern;
      
    tracef("updateBgmPlay need update\n");

    return true;
}

bool BgmCurtainPlay::startBgmDeal()
{ 
    m_palyDscribeMutex.lock();
    if(!CurtainActManager::instance()->getJsonTable(m_streamerDescPath, m_bgmListTable))
    {
        LOG_PrintError("Default Streamer Curtain get faild!!\n");
        m_palyDscribeMutex.unlock();
        return false;
    }
    m_palyDscribeMutex.unlock();

    if(!bgmDescribeCheckout(m_bgmListTable, "", ""))
    {
        LOG_PrintError("m_bgmListTable checkout failed\n");
        return false; 
    }

    m_palyDscribeMutex.lock();
	CurtainActManager::instance()->setJsonTable(m_streamerDescPath, m_bgmListTable);
	m_palyDscribeMutex.unlock();
	LOG_PrintWarn("m_bgmListTable write---> %s\n", m_bgmListTable.toStyledString().c_str());


    return true;
}

bool BgmCurtainPlay::getDownloadUrl(std::vector<std::string>& urls)
{
    if(!m_bgmListTable.isMember("bgmlist"))
	{
        LOG_PrintError("json params error\n");
        return false;
	}

	Json::Value streamInfo = m_bgmListTable["bgmlist"];
    Json::Value detailInfo = Json::nullValue;
	for(uint i = 0; i < streamInfo.size(); ++i)
	{
        detailInfo = streamInfo[i];
        if (!detailInfo.isMember("mediasource")
          || !detailInfo.isMember("pattern"))
        {
            continue;
        }

        std::string filename = detailInfo["mediasource"].asString();
        if(detailInfo["pattern"].asString() == "ONLINEMP4")
        {
            auto it = std::find(urls.begin(), urls.end(), filename);
            if (it == urls.end())
            {
                urls.push_back(filename);
            }
        }     
	}
	
    return true;
}


bool BgmCurtainPlay::stopUsbcardBgmCurtain(){
    if(m_rootPath == AIR_UDISK_PATH){
        stopBgmCurtain();
    }
    return true;
}

bool BgmCurtainPlay::playBgmCurtain(std::string rootPath){
	//清除上一组播放的横幅
	stopBgmCurtain();
	

    if(rootPath.empty()){
        if(m_rootPath.empty() || !DiskController::instance()->isMountPath(m_rootPath)){
            DiskController::instance()->setRealTimeRootPath();
            DiskController::instance()->getRealTimeRootPath(rootPath);
        }else{
            rootPath = m_rootPath;
        }
    }
    m_rootPath = rootPath;
    m_streamerPath = rootPath + BGM_ROOT_DIR;
    m_streamerDescPath = rootPath + std::string(BGM_ROOT_DIR) + std::string(BGM_DESCRIBE);
    
	//读取开始结束时间
	if(!CurtainActManager::instance()->getJsonTable(m_streamerDescPath, m_bgmListTable)){
        return false;
    }
	//LOG_PrintWarn("m_bgmListTable ---> %s\n", m_bgmListTable.toStyledString().c_str());

	if(!m_bgmListTable.isMember("relativestart")
	  || !m_bgmListTable.isMember("relativeend")
	  || !m_bgmListTable.isMember("type"))
	{
        LOG_PrintError("json params error\n");
        return false;
	}

	uint64_t curTime = vdo_get_time();
	uint64_t start =  m_bgmListTable["relativestart"].asUInt64() * 1000 + curTime;
	uint64_t end   =  m_bgmListTable["relativeend"].asUInt64() * 1000 + curTime;
	LOG_PrintInfo("start: %llu   end: %llu\n", start, end);
	if(end < start){
		LOG_PrintError("params error endtime < starttime \n");
		return false;
	}

	//设置横幅播放的标志位
	m_streamer = true;
	auto lam = [this](uint64_t start, uint64_t end){			
		//监听，根据时间看是否执行开启横幅或者关闭横幅的操作
		bool excuteFlg = true;
		while(m_streamer){
			//获取当前系统时间，如果时间大于要执行的任务，且任务没有开始执行就执行
			uint64_t time = vdo_get_time();
			if((time > start) && excuteFlg)
			{
			    excuteFlg = false;
                m_curPlayIndex = 0;
                if(!startBgmDeal())
                {
                    LOG_PrintError("startBgmDeal failed\n");
                    break;
                }
                thread streamerplay(&BgmCurtainPlay::updateBgmPlay, this);
                streamerplay.detach();

                if(m_bgmListTable["type"] == "online")
                {
                    std::vector<std::string> urls;
                    getDownloadUrl(urls);                    
                    if(!urls.empty())
                    {
                        auto downloadResultCb = [this](bool result, std::string url, std::string fileName){

                            LOG_PrintWarn("result =%d, url = %s, fileName=%s\n", result, url.c_str(), fileName.c_str());
                            if(result > 0)
                            {
                                changeDescribeInfo(url, fileName);
                            }
                        };

                        std::string path = m_streamerPath;

                        auto downloadStart = [downloadResultCb, urls, path]{
            
                            StreamerDownloadOnlineFile::instance(BGM)->start(urls, downloadResultCb, path);
                        };
                        thread downloadThread(downloadStart);
                        downloadThread.detach();
                    }
                }

			}

			if(time > end){
				thread stopStreamer(&BgmCurtainPlay::stopBgmCurtain, this);
				stopStreamer.detach();
			}
			std::this_thread::sleep_for(std::chrono::milliseconds(100 * 2));
		}
		m_streamerThread = true;
	};	
	thread streamer(lam, start, end);
	streamer.detach();
	return true;
}

bool BgmCurtainPlay::stopBgmCurtain(){
	lock_guard<mutex> lock(m_stopstreamLock);
	//如果当前正在监听前一组横幅的定时器需要停止
	if(m_streamer){
		m_streamer = false;

		//停止文件下载
        StreamerDownloadOnlineFile::instance(BGM)->stop();
        
		while(!m_streamerThread){
			std::this_thread::sleep_for(std::chrono::milliseconds(100 * 2));
		}
		m_streamerThread = false;

		//停止播放
        Mp4StreamType mp4Type = MP4_ONLINE_BGM;
        if(m_playPattern == "VIDEOFILE") 
        {
            mp4Type = MP4_LOCAL_BGM;
        }
        Mp4ClientStream::instance(mp4Type)->stop();
	}

	
	
	return true;
}

bool BgmCurtainPlay::compareMd5(std::string filename, const char *md5)
{
    bool ret = false;
	unsigned int size;
	unsigned char *pData;
	unsigned char outputTemp[16] = {0};
	const char *md = md5;

	if(filename.empty() || !md5)
	{
		errorf("params failed!\n");
		return false;
	}
	
	int fd = open(filename.c_str(),O_RDWR);
	if (fd < 0)
	{
		printf("open %d failed!\n", fd);
		return false;
	}
	size = lseek(fd, 0, SEEK_END);

	pData = (unsigned char *)mmap(NULL,
								  size,
								  PROT_READ,
								  MAP_PRIVATE,
								  fd,
								  0);
	md5_calc(outputTemp, pData, size);

	printf("md5 ------------------------ %s\n", md);
	uint8_t *mddd = (uint8_t *)md;
	printf("local md--->%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X \n", mddd[0],mddd[1], mddd[2], mddd[3], mddd[4],
				mddd[5], mddd[6], mddd[7], mddd[8], mddd[9], mddd[10], mddd[11], mddd[12], mddd[13], mddd[14], mddd[15]);
	printf("local md--->%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X \n", outputTemp[0],outputTemp[1], outputTemp[2], outputTemp[3], outputTemp[4],
				outputTemp[5], outputTemp[6], outputTemp[7], outputTemp[8], outputTemp[9], outputTemp[10], outputTemp[11], outputTemp[12], outputTemp[13], outputTemp[14], outputTemp[15]);

	if (memcmp(outputTemp, md5, 16) == 0)
	{
		LOG_PrintInfo("compareMd5 equal\n");
		ret = true;
	}
	else
	{	
        m_curfileMd5 = (char*)outputTemp;
    }
    
	munmap((void *)pData, size);
    close(fd);
	return ret;
}


bool BgmCurtainPlay::playNextBgm()
{
    LOG_PrintWarn("BgmCurtainPlay::playNextBgm enter\n");
    /*if(!m_streamer)
    {
        return false; 
    }*/

    if(!startBgmDeal())
    {
        LOG_PrintError("startBgmDeal failed\n");
        return false;
    }

    thread streamerplay(&BgmCurtainPlay::updateBgmPlay, this);
    streamerplay.detach();

    return true;   
}

bool BgmCurtainPlay::changeDescribeInfo(std::string url, std::string fileName)
{
    m_palyDscribeMutex.lock();
    if(!CurtainActManager::instance()->getJsonTable(m_streamerDescPath, m_bgmListTable))
    {
        LOG_PrintError("Default Streamer Curtain get faild!!\n");
        m_palyDscribeMutex.unlock();
        return false;
    }
    m_palyDscribeMutex.unlock();

    if(!bgmDescribeCheckout(m_bgmListTable, url, fileName))
    {
        LOG_PrintError("m_bgmListTable checkout failed\n");
        return false; 
    }

    m_palyDscribeMutex.lock();
	CurtainActManager::instance()->setJsonTable(m_streamerDescPath, m_bgmListTable);
	m_palyDscribeMutex.unlock();
	LOG_PrintWarn("m_bgmListTable write---> %s\n", m_bgmListTable.toStyledString().c_str());
	
    return true;
}

}




